#include <Python.h>
#include <structmember.h>
#include "tsminc.h"
#include "tsmfp.h"

#define EXTERN extern

#include "global.h"

#define DSMBEGINTXN   0x00
#define DSMENDTXN     0x01
#define DSMENDSENDOBJ 0x02


#define APPLICATION_TYPE "Python:Api"


typedef struct {
    PyObject_HEAD
    PyObject *dsmHandle;
    PyObject *dsmRC;
    PyObject *dsmConfigFile;
    PyObject *dsmOptions;
    PyObject *useUnicode;
    PyObject *bCrossPlatform;
    PyObject *inSession;
    PyObject *inTransaction;
    PyObject *inQuery;
    PyObject *QueryType;

} TsmApi;

/*
 * TsmApi_dealloc: Elimina referencias a los objectos miembros 
 *                 y libera la memoria
 * Parametros: self
 * Retorno:    void
 */

static void 
TsmApi_dealloc(TsmApi *self)
{
    Py_XDECREF(self->dsmHandle);
    Py_XDECREF(self->dsmRC);
    Py_XDECREF(self->dsmConfigFile);
    Py_XDECREF(self->dsmOptions);
    Py_XDECREF(self->useUnicode);
    Py_XDECREF(self->bCrossPlatform);
    Py_XDECREF(self->inSession);
    Py_XDECREF(self->inTransaction);
    Py_XDECREF(self->inQuery);
    Py_XDECREF(self->QueryType);
    self->ob_type->tp_free((PyObject *)self);
}

static PyObject *
TsmApi_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    TsmApi *self;
    
    self = (TsmApi *) type->tp_alloc(type, 0);
    if (self) {
	self->inSession     = Py_False;
	if (self->inSession == NULL) {
	    Py_XINCREF(Py_False);
	    Py_XDECREF(self);
	    return NULL;
	}
	
	self->inTransaction = Py_False;
	if (self->inTransaction == NULL) {
	    Py_XINCREF(Py_False);
	    Py_XDECREF(self);
	    return NULL;
	}
	
	self->inQuery	    = Py_False;
	if (self->inQuery == NULL) {
	    Py_XINCREF(Py_False);
	    Py_XDECREF(self);
	    return NULL;
	}
	

	self->dsmHandle     = PyLong_FromLong((long) 0);
	if (self->dsmHandle == NULL) {
	    Py_XDECREF(self);
	    return NULL;	
	}
	
	self->dsmConfigFile = PyString_FromString("");
	if (self->dsmConfigFile == NULL) {
	    Py_XDECREF(self);
	    return NULL;
	}
	
	self->dsmOptions    = Py_None;
	if (self->dsmOptions == NULL) {
	    Py_INCREF(Py_None);
	    Py_XDECREF(self);
	    return NULL;
	} 

	self->useUnicode    = Py_False;
	if (self->useUnicode == NULL) {
	    Py_XINCREF(Py_False);
	    Py_XDECREF(self);
	    return NULL;
	}
	
	self->bCrossPlatform = Py_False;
	if (self->bCrossPlatform == NULL) {
	    Py_XINCREF(Py_False);
	    Py_XDECREF(self);
	    return NULL;
	}
	
	self->dsmRC	    = PyInt_FromLong((long)0);
	if (self->dsmRC == NULL) {
	    Py_XDECREF(self);
	    return NULL;
	}
	
	self->QueryType     = PyInt_FromLong((long)0);
	if (self->QueryType == NULL) {
	    Py_XDECREF(self);
	    return NULL;	
	}
    
    }
    return (PyObject *) self;
}


static int
TsmApi_init(TsmApi *self, PyObject *args, PyObject *kwds)
{
    PyObject *dsmConfigFile  = NULL, 
	     *dsmOptions     = NULL, 
	     *useUnicode     = NULL, 
	     *bCrossPlatform = NULL, 
	     *tmp;
    
    static char *kwlist[] = {"dsmConfigFile", "dsmOptions", "useUnicode", "bCrossPlatform",  NULL};
    
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOO", kwlist, &dsmConfigFile, 
								  &dsmOptions, 
								  &useUnicode, 
								  &bCrossPlatform))
	return -1;
	
    if (dsmConfigFile) {
	if (PyString_Check(dsmConfigFile)) {
	    tmp = self->dsmConfigFile;
	    Py_INCREF(dsmConfigFile);
	    self->dsmConfigFile = dsmConfigFile;
	    Py_XDECREF(tmp);
	}
	else {
	    PyErr_SetString(PyExc_AttributeError, "dsmConfigFile must be string");
	    return -1;
	}
    }
    
    if (dsmOptions) {
	if (PyString_Check(dsmOptions)) {
	    tmp = self->dsmOptions;
	    Py_INCREF(dsmOptions);
	    self->dsmOptions = dsmOptions;
	    Py_XDECREF(tmp);
	}
	else {
	    PyErr_SetString(PyExc_AttributeError, "dsmOptions must be string");
	    return -1;
	}
    }
    
    if (useUnicode) { 
	if (PyBool_Check(useUnicode)) {
	    tmp = self->useUnicode;
	    Py_XINCREF(useUnicode);
	    self->useUnicode = useUnicode;
	    Py_XDECREF(tmp);
	}
	else {
	    PyErr_SetString(PyExc_AttributeError, "useUnicode must be Boolean"); 
	    return -1;
	}
    }
	
    if (bCrossPlatform) {
	if (PyBool_Check(bCrossPlatform)) {
	    tmp = self->bCrossPlatform;
	    Py_XINCREF(bCrossPlatform);
	    self->bCrossPlatform = bCrossPlatform;
	    Py_XDECREF(tmp);
	}
	else {
	    PyErr_SetString(PyExc_AttributeError, "bCrossPlatform must be Boolean");
	    return -1;
	}
    }
    
    QueryType = -1;
    objIDS   = NULL;
    pObjData = NULL;
    
    return 0;
}


static PyMemberDef TsmApi_members[] = {
    {"dsmHandle"      , T_OBJECT_EX, offsetof(TsmApi, dsmHandle)     , 0, "Session Handle" },
    {"dsmRC"          , T_OBJECT_EX, offsetof(TsmApi, dsmRC)         , 0, "Last Return Code" },
    {"dsmConfigFile"  , T_OBJECT_EX, offsetof(TsmApi, dsmConfigFile) , 0, "Config File"},
    {"dsmOptions"     , T_OBJECT_EX, offsetof(TsmApi, dsmOptions)    , 0, "Options"},
    {"useUnicode"     , T_OBJECT_EX, offsetof(TsmApi, useUnicode)    , 0, "Bool: Use unicode"},
    {"bCrossPlatform" , T_OBJECT_EX, offsetof(TsmApi, bCrossPlatform), 0, "Bool: Cross Platform"},
    {"inSession"      , T_OBJECT_EX, offsetof(TsmApi, inSession)     , 0, "Bool: In Session"},
    {"inTransaction"  , T_OBJECT_EX, offsetof(TsmApi, inTransaction) , 0, "Bool: In Trans"},
    {"inQuery"        , T_OBJECT_EX, offsetof(TsmApi, inQuery)       , 0, "Bool: In Query"},
    {"QueryType"      , T_OBJECT_EX, offsetof(TsmApi, QueryType)     , 0, "Query Type"},
    {NULL}
};

/**************************************************************************************
 * tsmReturnBeginQueryResult(): Funcion de apoyo que evalua el codigo de retorno dsmRC 
 *				luego de una llamada a funcion de dsmBeginQuery()
 **************************************************************************************/

static PyObject *
tsmReturnBeginQueryResult(TsmApi *self, dsInt16_t dsmRC)
{
    PyObject *tmp;
    
    tmp = self->dsmRC;
    Py_XDECREF(tmp);
    self->dsmRC = PyInt_FromLong((long) dsmRC);
    
    /*****************************************************
     * Si la llamada a funcion Falla retorna False
     *****************************************************/
    
    if (dsmRC)
	Py_RETURN_FALSE;
	
    /******************************************************
     * De lo contrario:
     *		      - Establece que se encuentra inQuery
     *		      - Establece en que tipo de Query esta
     *		      - Retorna TRUE
     ******************************************************/

    tmp = self->inQuery;
    Py_XDECREF(tmp);
    self->inQuery = Py_True;
    Py_XINCREF(self->inQuery);

    tmp = self->QueryType;
    Py_XDECREF(tmp);
    self->QueryType = PyLong_FromLong( (long) QueryType);

    Py_RETURN_TRUE;
}


/************************************************************
 * tsmInitEx(): Esta funcion es la homologa de la API de tsm
 * 		pero tiene menos argumentos, ya que otros
 *		argumentos de la funcion original son pasados
 *		en init()
 ************************************************************/
static PyObject *
tsmInitEx ( TsmApi *self, PyObject *args, PyObject *kwds )
{
    dsUint32_t dsmHandle;
    dsInt16_t  dsmRC;
    
    PyObject *cNodeNameP    = NULL, 
	     *cOwnerNameP   = NULL, 
	     *cPasswordP    = NULL, 
	     *userNameP     = NULL, 
	     *userPasswordP = NULL, 
	     *tmp;

    static char *kwlist[] = {"cNodeNameP", "cOwnerNameP", "cPasswordP", "userNameP", "userPasswordP", NULL};

    /******************************************************************
     * La funcion tsmInitEx() recibe los siguientes argumentos:
     *			- cNodeNameP:    Obligatorio
     *			- cOwnerNameP:   Obligatorio
     *			- cPasswordP:    Obligatorio
     *			- userNameP:     Opcional
     *			- userPasswordP: Opcional
     ******************************************************************/

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|OO", kwlist, &cNodeNameP,
								   &cOwnerNameP, 
								   &cPasswordP, 
								   &userNameP, 
								   &userPasswordP))
	return NULL;

    /******************************************************************
     * Inicializan las estructuras de E/S para la funcion dsmInitEx()
     ******************************************************************/
    memset(&dsmInitIn,  0, sizeof(dsmInitExIn_t ));
    memset(&dsmInitOut, 0, sizeof(dsmInitExOut_t));


    /******************************************************************
     * Consulta sobre la version de la API
     ******************************************************************/
    dsmQueryApiVersionEx(&apiVersion);

    /******************************************************************
     * Se completa la estructura dsmInitIn
     ******************************************************************/
    dsmInitIn.apiVersionExP    = &apiVersion;
    dsmInitIn.stVersion        = dsmInitExInVersion;
    dsmInitIn.configfile       = PyString_AsString(self->dsmConfigFile);
    dsmInitIn.applicationTypeP = APPLICATION_TYPE; 

    if (self->dsmOptions  == Py_None)
	dsmInitIn.options = NULL;
    else
	dsmInitIn.options = PyString_AsString(self->dsmOptions);


    if (self->useUnicode == Py_True)
	dsmInitIn.useUnicode = bTrue;
    else
	dsmInitIn.useUnicode = bFalse;

    if (self->bCrossPlatform == Py_True)
	dsmInitIn.bCrossPlatform = bTrue;
    else
	dsmInitIn.bCrossPlatform = bFalse;


    if (cNodeNameP) {
	if (PyString_Check(cNodeNameP))
	    dsmInitIn.clientNodeNameP = PyString_AsString(cNodeNameP);
	else
	    dsmInitIn.clientNodeNameP = NULL;
    }
    else
	dsmInitIn.clientNodeNameP = NULL;
	

    if (cOwnerNameP) {
	if (PyString_Check(cOwnerNameP))
	    dsmInitIn.clientOwnerNameP = PyString_AsString(cOwnerNameP);
	else
	    dsmInitIn.clientOwnerNameP = NULL;
    }
    else
	dsmInitIn.clientOwnerNameP = NULL;


    if (cPasswordP) {
	if (PyString_Check(cPasswordP))
	    dsmInitIn.clientPasswordP = PyString_AsString(cPasswordP);
	else
	    dsmInitIn.clientPasswordP = NULL;
    }
    else
	dsmInitIn.clientPasswordP = NULL;
	
	
    /*******************************************************************
     * Una vez que se armo la estructura dsmInitIn se llama a la funcion
     * dsmInitEx()
     *
     * Siempre asigna el atributo dsmRC al valor devuelto por dsmInitEx()
     * Si - ret =  0 -> Compone la tupla y la retorna
     *    - ret != 0 -> Retorna Py_None
     *******************************************************************/
    dsmRC = dsmInitEx(&dsmHandle, &dsmInitIn, &dsmInitOut);
    tmp = self->dsmRC;
    Py_XDECREF(tmp);
    self->dsmRC = PyInt_FromLong( (long) dsmRC);
    if (dsmRC)
	Py_RETURN_NONE;

    tmp = self->inSession;
    Py_XDECREF(tmp);
    self->inSession = Py_True;
    Py_XINCREF(self->inSession);

    tmp = self->dsmHandle;
    Py_XDECREF(tmp);
    
    /*******************************************************************
     * Asigna el atributo dsmHandle al valor devuelto por dsmInitEx()
     *******************************************************************/

    self->dsmHandle = PyLong_FromLong( (long) dsmHandle );

    /*******************************************************************
     * Compone la Tupla de retorno basada en la estructura dsmIntExOut_t
     * Los valores h y s del primer argumento representan:
     * 			- h = Short
     * 			- s = String
     *
     *******************************************************************/
    return Py_BuildValue("(hhshhhh)", 
			  dsmInitOut.userNameAuthorities, 
			  dsmInitOut.infoRC, 
			  dsmInitOut.adsmServerName, 
			  dsmInitOut.serverVer, 
			  dsmInitOut.serverRel, 
			  dsmInitOut.serverLev, 
			  dsmInitOut.serverSubLev);
}


/***********************************************************************
 * tsmTerminate(): Finaliza la secion comenzada por tsmInitEx()
 ***********************************************************************/
static PyObject*
tsmTerminate(TsmApi *self)
{
    PyObject *tmp;
    dsUint32_t dsmHandle;
    dsInt16_t  dsmRC;
    
    /*****************************************************************
     * Chequea en primera instancia que exista una session
     *****************************************************************/
    
    if (self->inSession == Py_True) {
	dsmHandle = (dsUint32_t) PyLong_AsLong( self->dsmHandle );
	dsmRC = dsmTerminate(dsmHandle);
	tmp = self->dsmRC;
	Py_XDECREF(tmp);
	self->dsmRC = PyInt_FromLong((long) dsmRC);
	
	/************************************************************
	 * Si no pudo terminar la session Retorna False, de lo
	 * contrario retorna True
	 ************************************************************/
	
	if (dsmRC)
	    Py_RETURN_FALSE;
	else {
	    tmp = self->inSession;
	    Py_XDECREF(tmp);
	    self->inSession = Py_False;
	    Py_XINCREF(self->inSession);
	    Py_RETURN_TRUE;
	}
    }
    Py_RETURN_TRUE;
}


static PyObject*
tsmGenericFn(TsmApi *self, unsigned char fntype)
{
    PyObject *tmp;
    dsUint32_t dsmHandle;
    dsInt16_t  dsmRC;

    dsmHandle = (dsUint32_t) PyLong_AsLong( self->dsmHandle );

    switch (fntype)
    {
	case DSMBEGINTXN:
	    dsmRC = dsmBeginTxn(dsmHandle);
    	    break;
    	case DSMENDTXN:
	    dsmRC = dsmEndTxn(dsmHandle);
	    break;
	case DSMENDSENDOBJ:
	    dsmRC = dsmEndSendObj(dsmHandle);
    }
    tmp = self->dsmRC;
    Py_XDECREF(tmp);
    self->dsmRC = PyInt_FromLong(dsmRC);

    if (dsmRC)
	Py_RETURN_FALSE;
	
    Py_RETURN_TRUE;
}

static PyObject*
tsmBeginTxn(TsmApi *self)
{
    return tsmGenericFn(self, DSMBEGINTXN);
}

static PyObject*
tsmEndTxn(TsmApi *self)
{
    return tsmGenericFn(self, DSMENDTXN);
}

static PyObject*
tsmEndSendObj(TsmApi *self)
{
    return tsmGenericFn(self, DSMENDSENDOBJ);
}

static PyObject *
tsmBeginQueryFS (TsmApi *self, PyObject *args, PyObject *kwds)
{
    PyObject *fsName = NULL;
    
    dsInt16_t  dsmRC;
    dsUint32_t dsmHandle;
    qryFSData  buff;
    
    static char *kwlist[] = {"fsName", NULL};
    
    memset(&buff, 0, sizeof(qryFSData));
    
    if (self->inSession == Py_False) 
	Py_RETURN_FALSE;

    if (self->inQuery == Py_True)
	Py_RETURN_FALSE;
    
    
    if (! PyArg_ParseTupleAndKeywords (args, kwds, "O", kwlist, &fsName))
	return NULL;

    if (fsName) {
	if (PyString_Check(fsName))
	    buff.fsName = PyString_AsString(fsName);
	else
	    buff.fsName = NULL;
    }

    


    dsmHandle = PyLong_AsLong(self->dsmHandle);
    dsmRC = dsmBeginQueryFS(dsmHandle, &buff);

    /********************************************************
     * Llamada a la funcion de apoyo para evaluar el retorno
     ********************************************************/

    return tsmReturnBeginQueryResult(self, dsmRC);
}


static PyObject *
tsmBeginQueryArchive(TsmApi *self, PyObject *args, PyObject *kwds)
{
    PyObject *objName = NULL,
	     *owner   = NULL,
	     *insDateLowerBound = NULL,
	     *insDateUpperBound = NULL,
	     *expDateLowerBound = NULL,
	     *expDateUpperBound = NULL,
	     *descr = NULL;

    char *fs, *hl, *ll;
	     
    qryArchiveData buff;
    dsmObjName     oName;
    dsInt16_t	   dsmRC;
    dsUint32_t	   dsmHandle;
    
    static char *kwlist[] = { "objName", 
			      "owner", 
			      "insDateLowerBound", 
			      "insDateUpperBound", 
			      "expDateLowerBound",
			      "expDateUpperBound", NULL };


    memset(&buff,  0, sizeof(qryArchiveData));
    memset(&oName, 0, sizeof(dsmObjName));

    if (self->inSession == Py_False) 
	Py_RETURN_FALSE;

    if (self->inQuery == Py_True)
	Py_RETURN_FALSE;



    if ( !PyArg_ParseTupleAndKeywords ( args, kwds, "OO|OOOOO", kwlist, &objName, 
								        &owner,
								        &insDateLowerBound,
	    							        &insDateUpperBound,
	    							        &expDateLowerBound,
	    							        &expDateUpperBound,
	    							        &descr ))
	return NULL; 
    
    
    if (objName) {
	if (PyTuple_Check(objName)) {
	    if ( !PyArg_ParseTuple (objName, "sssB", &fs, &hl, &ll, &oName.objType) )
		return NULL;
	    strcpy(oName.fs, fs);
	    strcpy(oName.hl, hl);
	    strcpy(oName.ll, ll);
	    buff.objName = &oName;
	}
	else {
	    PyErr_SetString(PyExc_AttributeError, "objName must be a Tuple");
	    return NULL;
	}
    }
    if (owner) {
	if (PyString_Check(owner))
	    buff.owner = PyString_AsString(owner);
	else if (owner == Py_None)
	    buff.owner = NULL;
	else {
	    PyErr_SetString(PyExc_AttributeError, "owner must be a String or None");
	    return NULL;
	}
    }
    
    
    if (insDateLowerBound) {
	if (PyTuple_Check(insDateLowerBound)) {
	    if ( !PyArg_ParseTuple (insDateLowerBound, "HBBBBB", &buff.insDateLowerBound.year, 
								 &buff.insDateLowerBound.month, 
								 &buff.insDateLowerBound.day, 
								 &buff.insDateLowerBound.hour, 
								 &buff.insDateLowerBound.minute, 
								 &buff.insDateLowerBound.second) )
		return NULL;
	}
	else if (insDateLowerBound == Py_None) 
	    buff.insDateLowerBound.year = DATE_MINUS_INFINITE;
    }
    else 
	buff.insDateLowerBound.year = DATE_MINUS_INFINITE;
    
    if (insDateUpperBound) {
	if (PyTuple_Check(insDateUpperBound)) {
	    if ( !PyArg_ParseTuple (insDateUpperBound, "HBBBBB", &buff.insDateUpperBound.year, 
								 &buff.insDateUpperBound.month, 
								 &buff.insDateUpperBound.day, 
								 &buff.insDateUpperBound.hour, 
								 &buff.insDateUpperBound.minute, 
								 &buff.insDateUpperBound.second) )
		return NULL;
	}
	else if (insDateUpperBound == Py_None) 
	    buff.insDateUpperBound.year = DATE_PLUS_INFINITE;
    }
    else 
	buff.insDateUpperBound.year = DATE_PLUS_INFINITE;
    
    
    if (expDateLowerBound) {
	if (PyTuple_Check(expDateLowerBound)) {
	    if ( !PyArg_ParseTuple (expDateLowerBound, "HBBBBB", &buff.expDateLowerBound.year, 
								 &buff.expDateLowerBound.month, 
								 &buff.expDateLowerBound.day, 
								 &buff.expDateLowerBound.hour, 
								 &buff.expDateLowerBound.minute, 
								 &buff.expDateLowerBound.second) )
		return NULL;
	}
	else if (expDateLowerBound == Py_None) 
	    buff.expDateLowerBound.year = DATE_MINUS_INFINITE;
    }
    else 
	buff.expDateLowerBound.year = DATE_MINUS_INFINITE;
    
    if (insDateUpperBound) {
	if (PyTuple_Check(expDateUpperBound)) {
	    if ( !PyArg_ParseTuple (expDateUpperBound, "HBBBBB", &buff.expDateUpperBound.year, 
								 &buff.expDateUpperBound.month, 
								 &buff.expDateUpperBound.day, 
								 &buff.expDateUpperBound.hour, 
								 &buff.expDateUpperBound.minute, 
								 &buff.expDateUpperBound.second) )
		return NULL;
	}
	else if (expDateUpperBound == Py_None) 
	    buff.expDateUpperBound.year = DATE_PLUS_INFINITE;
    }
    else 
	buff.expDateUpperBound.year = DATE_PLUS_INFINITE;
    
    
    if (descr) {
	if (PyString_Check(descr))
	    buff.descr = PyString_AsString(descr);
	else if (descr == Py_None)
	    buff.descr = "*";
    }
    else 
	buff.descr = "*"; 
    
    dsmHandle = PyLong_AsLong(self->dsmHandle);
    dsmRC = dsmBeginQueryArchive(dsmHandle, &buff);
    
    
    return tsmReturnBeginQueryResult(self, dsmRC);
}

/*******************************************************************
 * tsmEndGetData(): homologa a dsmEndGetData()
 *******************************************************************/
static PyObject *
tsmEndGetData (TsmApi *self)
{
    PyObject *tmp;
    dsInt16_t dsmRC;
    dsUint32_t dsmHandle;
    
    dsmHandle = (dsUint32_t) PyLong_AsLong(self->dsmHandle);

    dsmRC = dsmEndGetData(dsmHandle);
    tmp = self->dsmRC;
    Py_XDECREF(tmp);
    self->dsmRC = PyInt_FromLong((long) dsmRC);
    
    if (objIDS) {
	free(objIDS);
	objIDS = NULL;
    }

    if (pObjData) {
	free(pObjData);
	pObjData = NULL;
    }
    
    if (dsmRC)
	Py_RETURN_TRUE;
	
    Py_RETURN_FALSE;
}

/*******************************************************************
 * tsmEndGetObj(): homologa a dsmEndGetObj()
 *******************************************************************/
static PyObject *
tsmEndGetObj (TsmApi *self)
{
    PyObject *tmp;
    dsInt16_t dsmRC;
    dsUint32_t dsmHandle;
    
    dsmHandle = (dsUint32_t) PyLong_AsLong(self->dsmHandle);

    dsmRC = dsmEndGetObj(dsmHandle);
    tmp = self->dsmRC;
    Py_XDECREF(tmp);
    self->dsmRC = PyInt_FromLong((long) dsmRC);
    
    if (dsmRC)
	Py_RETURN_FALSE;
	
    Py_RETURN_TRUE;
}


static PyObject *
tsmBeginQueryMC (TsmApi *self, PyObject *args, PyObject *kwds)
{
    PyObject *mcName   = NULL,
	     *mcDetail = NULL;

    qryMCData buff;
    dsInt16_t  dsmRC;
    dsUint32_t dsmHandle;
    
    static char *kwlist[] = { "mcName", "mcDetail", NULL };
    
    memset(&buff, 0, sizeof(qryMCData));
    
    
    if (self->inSession == Py_False) 
	Py_RETURN_FALSE;

    if (self->inQuery == Py_True)
	Py_RETURN_FALSE;

    
    
    if (! PyArg_ParseTupleAndKeywords (args, kwds, "O|O", kwlist, &mcName, &mcDetail))
	return NULL;
    
    if (mcName) {
	if (PyString_Check(mcName)) 
	    buff.mcName = PyString_AsString(mcName);
	else
	    buff.mcName = NULL;
    }
    
    if (mcDetail) {
	if (PyBool_Check(mcDetail)) {
	    if (mcDetail == Py_True)
		buff.mcDetail = bFalse; /* Omitir de momento pedir los detalles */
	    else
		buff.mcDetail = bFalse;
	}
	else
	    buff.mcDetail = bFalse;
    }

    dsmHandle = PyLong_AsLong(self->dsmHandle);
    dsmRC = dsmBeginQueryMC(dsmHandle, &buff);

    return tsmReturnBeginQueryResult(self, dsmRC);
}


static PyObject *
tsmGetNextQObj(TsmApi *self)
{
    PyObject *tmp;
    dsInt16_t  dsmRC;
    dsUint32_t dsmHandle;
    qryRespMCData MCBuff;
    qryRespFSData FSBuff;
    qryRespArchiveData ArchiveBuff;
    char tmpStr[DSM_MAX_OBJINFO_LENGTH];
    
    if (self->inSession == Py_True)
	if (self->inQuery == Py_True) {
	
	    dsmHandle = (dsUint32_t) PyLong_AsLong(self->dsmHandle);
	
	    switch(QueryType) {
	    
		/***************************************************************
		 * Query Type Management Class
		 ***************************************************************/
	    
		case qtMC:
		    dsmRC = dsmGetNextQMCObj(dsmHandle, &MCBuff);
		    tmp = self->dsmRC;
		    Py_XDECREF(tmp);
		    self->dsmRC = PyInt_FromLong((long) dsmRC);
		    
		    if (dsmRC == DSM_RC_MORE_DATA) {
			/********************************************************
			 * Retona la Tupla (mcName, McDesc)
			 ********************************************************/
			return Py_BuildValue("(ss)", MCBuff.mcName, MCBuff.mcDesc);
		    }
		    else  
			Py_RETURN_NONE;
			
		    break;
		
		/***************************************************************
		 * Query Type Filespace
		 ***************************************************************/
		case qtFilespace:
		    dsmRC = dsmGetNextQFSObj(dsmHandle, &FSBuff);
		    tmp = self->dsmRC;
		    Py_XDECREF(tmp);
		    self->dsmRC = PyInt_FromLong((long) dsmRC);
		    
		    if (dsmRC == DSM_RC_MORE_DATA) {
			/*
			 * Retorna la Tupla ()
			 */
			return Py_BuildValue("(ss(kk)(kk)(HBBBBB)(HBBBBB))",
						FSBuff.fsName,
						FSBuff.fsType,
						FSBuff.occupancy.hi,
						FSBuff.occupancy.lo,
						FSBuff.capacity.hi,
						FSBuff.capacity.lo,
						FSBuff.backStartDate.year,
						FSBuff.backStartDate.month,
						FSBuff.backStartDate.day,
						FSBuff.backStartDate.hour,
						FSBuff.backStartDate.minute,
						FSBuff.backStartDate.second,
						FSBuff.backCompleteDate.year,
						FSBuff.backCompleteDate.month,
						FSBuff.backCompleteDate.day,
						FSBuff.backCompleteDate.hour,
						FSBuff.backCompleteDate.minute,
						FSBuff.backCompleteDate.second
					    );
		    }
		    else 
			Py_RETURN_NONE;
		    
		    break;
		
		/***************************************************************
		 * Query Type Archive
		 ***************************************************************/
				
		case qtArchive:
		    dsmRC = dsmGetNextQArchiveObj(dsmHandle, &ArchiveBuff);
		    tmp = self->dsmRC;
		    Py_XDECREF(tmp);
		    self->dsmRC = PyInt_FromLong((long) dsmRC);
		    
		    if (dsmRC == DSM_RC_MORE_DATA) {
			/*
			 * Retorna la Tupla ()
			 */
			strncpy(tmpStr, ArchiveBuff.objInfo, ArchiveBuff.objInfolen);
			return Py_BuildValue("(sss)kss(kk)(kk)B(HBBBBB)(HBBBBB)sHs(kkkkk)(kk)B",
					    ArchiveBuff.objName.fs,
					    ArchiveBuff.objName.hl,
					    ArchiveBuff.objName.ll,
					    ArchiveBuff.copyGroup,             /* Copy Group number */
					    ArchiveBuff.mcName,                /* mc name */
					    ArchiveBuff.owner,                 /* owner name */
					    ArchiveBuff.objId.hi,	       /* Unique copy ID */
					    ArchiveBuff.objId.lo,	
					    ArchiveBuff.reserved.hi,           /* backward compatibility */
					    ArchiveBuff.reserved.lo,	
					    ArchiveBuff.mediaClass,            /* media access class */
					    ArchiveBuff.insDate.year,          /* archive insertion date */
					    ArchiveBuff.insDate.month,
					    ArchiveBuff.insDate.day,
					    ArchiveBuff.insDate.hour,
					    ArchiveBuff.insDate.minute,
					    ArchiveBuff.insDate.second,
					    ArchiveBuff.expDate.year,          /* expiration date for object */
					    ArchiveBuff.expDate.month,
					    ArchiveBuff.expDate.day,
					    ArchiveBuff.expDate.hour,
					    ArchiveBuff.expDate.minute,
					    ArchiveBuff.expDate.second,
					    ArchiveBuff.descr,		       /* archive description */
					    ArchiveBuff.objInfolen,	       /* length of object-dependent information*/
					    tmpStr,			       /* object-dependent information */
					    ArchiveBuff.restoreOrderExt.top,   /* restore order */
					    ArchiveBuff.restoreOrderExt.hi_hi, 
					    ArchiveBuff.restoreOrderExt.hi_lo,
					    ArchiveBuff.restoreOrderExt.lo_hi,
					    ArchiveBuff.restoreOrderExt.lo_lo,
					    ArchiveBuff.sizeEstimate.hi,       /* size estimate stored by user*/
					    ArchiveBuff.sizeEstimate.lo,
					    ArchiveBuff.compressType);
		    }
		    else 
			Py_RETURN_NONE;
		    break;
	    }
	}
	
    Py_RETURN_NONE;
}


static PyObject *
tsmEndQuery(TsmApi *self)
{
    PyObject *tmp;
    dsInt16_t  dsmRC;
    dsUint32_t dsmHandle;
    
    if (self->inSession == Py_True) 
	if (self->inQuery == Py_True) {
	    dsmHandle = (dsUint32_t) PyLong_AsLong(self->dsmHandle);
	    dsmRC = dsmEndQuery(dsmHandle);
	    tmp   = self->dsmRC;
	    Py_XDECREF(tmp);
	    self->dsmRC = PyInt_FromLong((long) dsmRC);
	    tmp   = self->inQuery;
	    Py_XDECREF(tmp);
	    self->inQuery = Py_False;
	    Py_XINCREF(self->inQuery); 
	}
    Py_RETURN_TRUE;
}


static PyObject *
tsmRCMsg(TsmApi *self)
{
    PyObject   *tmp;
    dsInt16_t  dsmRC;
    dsUint32_t dsmHandle;
    
    dsmHandle = (dsUint32_t) PyLong_AsLong(self->dsmHandle);
    dsmRC = (dsInt16_t) PyInt_AsLong(self->dsmRC);
    dsmRC = dsmGetRCMsg(dsmHandle, dsmRC);
    tmp   = self->dsmRC;
    Py_XDECREF(tmp);
    self->dsmRC = PyInt_FromLong((long) dsmRC);
    
    return PyString_FromString(RCMsg);
}


static PyObject *
tsmGetObj (TsmApi *self, PyObject *args, PyObject *kwds)
{
    PyObject   *objID = NULL, *tmp;
    dsInt16_t  dsmRC;
    dsUint32_t dsmHandle;
    ObjID      ObjIDdata;

    static char *kwlist[] = { "objID", NULL };
    
    if ( !PyArg_ParseTupleAndKeywords (args, kwds, "O", kwlist, &objID) )
	return NULL;

    if (objID) {
	if (PyTuple_Check(objID)) {
	    if (!PyArg_ParseTuple(objID, "kk", &ObjIDdata.hi, &ObjIDdata.lo))
		return NULL; 
	}
	else {
	    PyErr_SetString(PyExc_AttributeError, "objName must be a Tuple");
	    return NULL;
	} 

	dsmHandle = (dsUint32_t) PyLong_AsLong(self->dsmHandle);
	

	memset(&qData, 0, sizeof(DataBlk));
	memset(IObuffer, 0, MBYTE);

	qData.stVersion  = DataBlkVersion;
	qData.bufferLen = MBYTE;
        qData.bufferPtr = (char *)IObuffer;
    
	dsmRC = dsmGetObj(dsmHandle, &ObjIDdata, &qData);
	tmp = self->dsmRC;
	Py_XDECREF(tmp);
	self->dsmRC = PyInt_FromLong((long) dsmRC);

	if (dsmRC == DSM_RC_MORE_DATA || dsmRC ==  DSM_RC_FINISHED) 
	    return PyByteArray_FromStringAndSize(qData.bufferPtr, qData.numBytes);
    }
    
    Py_RETURN_NONE;
}

static PyObject *
tsmGetData (TsmApi *self)
{
    PyObject   *tmp;
    dsInt16_t  dsmRC;
    dsUint32_t dsmHandle;

    if (self->inSession == Py_False)
	Py_RETURN_NONE;


    dsmHandle = (dsUint32_t) PyLong_AsLong(self->dsmHandle);
    
    memset(&qData,    0, sizeof(DataBlk));
    memset(IObuffer,  0, MBYTE);

    qData.stVersion  = DataBlkVersion;
    qData.bufferLen = MBYTE;
    qData.bufferPtr = (char *)IObuffer;
    
    dsmRC = dsmGetData(dsmHandle, &qData);
    
    tmp = self->dsmRC;
    Py_XDECREF(tmp);
    self->dsmRC = PyInt_FromLong((long) dsmRC);
    
    if (dsmRC == DSM_RC_MORE_DATA || dsmRC ==  DSM_RC_FINISHED) 
	return PyByteArray_FromStringAndSize(qData.bufferPtr, qData.numBytes);

    Py_RETURN_NONE;
}


static PyObject *
tsmBeginGetData (TsmApi *self, PyObject *args, PyObject *kwds)
{
    dsInt16_t  dsmRC;
    dsUint32_t dsmHandle;
    dsBool_t   mWait = bFalse;
    dsmGetType gType = gtArchive;
    dsmGetList gList;
    
    int i;
    
    Py_ssize_t lstSize;
    PyObject *tmp,
	     *mountWait      = NULL,
	     *getType        = NULL,
	     *dsmGetObjListP = NULL;

    static char *kwlist[] = { "mountWait", "getType", "dsmGetObjListP", NULL };
    
    if (! PyArg_ParseTupleAndKeywords (args, kwds, "OOO", kwlist, &mountWait, &getType, &dsmGetObjListP)) 
	return NULL;

    if (mountWait) {
	if (PyBool_Check(mountWait)) {
	    if (mountWait == Py_True)
		mWait = bTrue;
	    else
		mWait = bFalse;
	}
	else {
	    PyErr_SetString(PyExc_AttributeError, "mountWait must be a bool");
	    return NULL;
	}
    }
    
    if (getType) {
	if (PyInt_Check(getType)) 
	    gType = (dsmGetType) PyInt_AsLong(getType);
	else {
	    PyErr_SetString(PyExc_AttributeError, "getType must be a Int");
	    return NULL;
	}
    }
    if (dsmGetObjListP) {
	if ( ! PyList_Check(dsmGetObjListP)) {
	    PyErr_SetString(PyExc_AttributeError, "dsmGetObjListP must be a List");
	    return NULL;
	}
    }
    
    lstSize = PyList_Size(dsmGetObjListP);

    objIDS = malloc(sizeof(ObjID) * lstSize);
    if (! objIDS) {
	PyErr_SetString(PyExc_RuntimeError, "Out of memory");
	return NULL;
    }
    
    for ( i = 0; i <= lstSize-1; i++ ) {
	tmp = PyList_GetItem(dsmGetObjListP, (Py_ssize_t) i);
	if (! tmp ) {
	    free(objIDS);
	    return NULL;
	}
	if (! PyTuple_Check(tmp)) {
	    PyErr_SetString(PyExc_AttributeError, "dsmGetObjListP elements must be a Tuple");
	    free(objIDS);
	    return NULL;
	} 
	    
	if (! PyArg_ParseTuple(tmp, "kk", &objIDS[i].hi, &objIDS[i].lo)) {
	    free(objIDS);
	    return NULL;
	}
	Py_XDECREF(tmp);
    }

    gList.stVersion = dsmGetListVersion;
    gList.partialObjData = NULL;
    gList.numObjId       = (dsUint32_t) lstSize;
    gList.objId		 = objIDS;
    
    dsmHandle = PyLong_AsLong(self->dsmHandle);
    dsmRC     = dsmBeginGetData(dsmHandle, mWait, gType, &gList);


    tmp = self->dsmRC;
    Py_XDECREF(tmp);
    self->dsmRC = PyInt_FromLong((long) dsmRC);
    
    if (dsmRC)
	Py_RETURN_FALSE;

    Py_RETURN_TRUE;
}


static PyMethodDef TsmApi_methods[] = {
    {"tsmInitEx",            (PyCFunction)tsmInitEx,            METH_VARARGS, "Init Session"},
    {"tsmTerminate",         (PyCFunction)tsmTerminate,         METH_NOARGS,  "Terminate Session"},
    {"tsmBeginQueryMC",      (PyCFunction)tsmBeginQueryMC,      METH_VARARGS, "Begin MC Query"},
    {"tsmBeginQueryFS",      (PyCFunction)tsmBeginQueryFS,      METH_VARARGS, "Begin FS Query"},
    {"tsmBeginQueryArchive", (PyCFunction)tsmBeginQueryArchive, METH_VARARGS, "Begin Archive Query"},
    {"tsmGetNextQObj",       (PyCFunction)tsmGetNextQObj,       METH_NOARGS,  "Get Next Object"},
    {"tsmEndQuery",          (PyCFunction)tsmEndQuery,          METH_NOARGS,  "End of Query"},
    {"tsmRCMsg",             (PyCFunction)tsmRCMsg,	        METH_NOARGS,  "Get MSG from last Return Code"},
    {"tsmGetData", 	     (PyCFunction)tsmGetData, 		METH_NOARGS,  "Get data"},
    {"tsmEndGetData", 	     (PyCFunction)tsmEndGetData, 	METH_NOARGS,  "End get data"},
    {"tsmEndGetObj",	     (PyCFunction)tsmEndGetObj,         METH_NOARGS,  "End get Object"},
    {"tsmGetObj", 	     (PyCFunction)tsmGetObj, 		METH_VARARGS, "Get Object"},
    {"tsmBeginGetData",      (PyCFunction)tsmBeginGetData,	METH_VARARGS, "Begin Get Data"},
    {NULL}
};

static PyTypeObject TsmApiType = {
    PyObject_HEAD_INIT(NULL)
    0,                         /*ob_size*/
    "TsmApi.TsmApi",           /*tp_name*/
    sizeof(TsmApi),            /*tp_basicsize*/
    0,                         /*tp_itemsize*/
    (destructor)TsmApi_dealloc,/*tp_dealloc*/
    0,                         /*tp_print*/
    0,                         /*tp_getattr*/
    0,                         /*tp_setattr*/
    0,                         /*tp_compare*/
    0,                         /*tp_repr*/
    0,                         /*tp_as_number*/
    0,                         /*tp_as_sequence*/
    0,                         /*tp_as_mapping*/
    0,                         /*tp_hash */
    0,                         /*tp_call*/
    0,                         /*tp_str*/
    0,                         /*tp_getattro*/
    0,                         /*tp_setattro*/
    0,                         /*tp_as_buffer*/
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
    "TsmApi objects",          /* tp_doc */
    0,		               /* tp_traverse */
    0,		               /* tp_clear */
    0,		               /* tp_richcompare */
    0,		               /* tp_weaklistoffset */
    0,		               /* tp_iter */
    0,		               /* tp_iternext */
    TsmApi_methods,            /* tp_methods */
    TsmApi_members,            /* tp_members */
    0,                         /* tp_getset */
    0,                         /* tp_base */
    0,                         /* tp_dict */
    0,                         /* tp_descr_get */
    0,                         /* tp_descr_set */
    0,                         /* tp_dictoffset */
    (initproc)TsmApi_init,     /* tp_init */
    0,                         /* tp_alloc */
    TsmApi_new,                /* tp_new */
};



#ifndef PyMODINIT_FUNC	/* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
initTsmApi(void) 
{
    PyObject* m;
    
    if (PyType_Ready(&TsmApiType) < 0)
        return;
                
    m = Py_InitModule3("TsmApi", TsmApi_methods, "Tsm Api");
    
    if (m == NULL)
	 return;
                                             
    Py_INCREF(&TsmApiType);
    PyModule_AddObject(m, "TsmApi", (PyObject *)&TsmApiType);
}


